package com.daydayup.learn;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.*;

@Slf4j
public class ThreadPoolExceptionDemo {

    public static void main(String[] args) {
        // defaultSubmit();
        // getFuterSubmit();
        // defaultExecute();
        handleException();
    }

    static void handleException() {
        int cpuCoreNum = Runtime.getRuntime().availableProcessors();
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
                cpuCoreNum, cpuCoreNum*2, 1L, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(100)){
            @Override
            protected void afterExecute(Runnable r, Throwable t) {
                // execute运行
                if (t != null) {
                    log.error(t.getMessage(),t);
                }
                // submit运行
                if (t == null && r instanceof Future<?>) {
                    try {
                        Future<?> future = (Future<?>) r;
                        if (future.isDone()){
                            future.get();
                        }
                    } catch (InterruptedException e) {
                        t = e;
                        e.printStackTrace();
                    } catch (CancellationException e){
                        t = e;
                        e.printStackTrace();
                    } catch (ExecutionException ee){
                        t = ee.getCause();
                        ee.printStackTrace();
                    }
                }
            }
        };

        threadPool.execute(() -> {
            System.out.println(Thread.currentThread().getName()+"\t 进入线程池 submit方法");
            int x = 10/0;
            System.out.println(Thread.currentThread().getName()+"\t 进入线程池 submit方法 end");
        });
        finalOKShutdownNowAwaitTermination(threadPool);
    }

    /**
     * 默认的submit方法会吞掉异常
     */
    static void defaultSubmit() {
        ExecutorService threadPool = Executors.newFixedThreadPool(1);
        threadPool.submit(() -> {
            int s = 0;
            for (int i = 0; i < 10; i++) {
                System.out.println("i=" + i);
                if (i == 5) {
                   s = i/0;
                }
            }
            System.out.println("s="+s);
        });
        threadPool.shutdown();
    }

    /**
     * 获取线程池的返回值，可以获取到异常
     */
    static void getFuterSubmit() {
        ExecutorService threadPool = Executors.newFixedThreadPool(1);
        Future<?> future = threadPool.submit(() -> {
            int s = 0;
            for (int i = 0; i < 10; i++) {
                System.out.println("i=" + i);
                if (i == 5) {
                    s = i / 0;
                }
            }
            System.out.println("s=" + s);
        });
        try {
            future.get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        threadPool.shutdown();
    }

    /**
     * execute能够抛出线程中产生的异常
     */
    static void defaultExecute() {
        ExecutorService threadPool = Executors.newFixedThreadPool(1);
        threadPool.execute(() -> {
            int s = 0;
            for (int i = 0; i < 10; i++) {
                System.out.println("i=" + i);
                if (i == 5) {
                    s = i/0;
                }
            }
            System.out.println("s="+s);
        });
        threadPool.shutdown();
    }

    /**
     * 官方推荐的优雅关停
     * @param threadPool
     */
    static void finalOKShutdownNowAwaitTermination(ExecutorService threadPool){
        if (threadPool != null && !threadPool.isShutdown()) {
            threadPool.shutdown();
            try{
                if (!threadPool.awaitTermination(120, TimeUnit.SECONDS)) {
                    threadPool.shutdownNow();
                    if (!threadPool.awaitTermination(120, TimeUnit.SECONDS)) {
                        System.out.println("Pool did not terminate");
                    }
                }
            } catch (InterruptedException e){
                threadPool.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
    }
}
